#ifndef _ResourceManager_H__
#define _ResourceManager_H__

#include "Resource.h"
#include "ResourceGroupManager.h"
#include "IteratorWrapper.h"
#include "Common.h"
#include "DataStream.h"
#include "StringVector.h"
#include "ScriptLoader.h"

namespace PVM
{
	class ResourceManager : public ScriptLoader
	{
	public:
		PVM_AUTO_MUTEX
		ResourceManager();
		virtual ~ResourceManager();
		
		virtual ResourcePtr create(const std::string& name, const std::string& group,
								   bool isManual = false, ManualResourceLoader* loader = 0,
								   const NameValuePairList* createParams = 0);
		typedef std::pair<ResourcePtr, bool> ResourceCreateOrRetrieveResult;
		
		virtual ResourceCreateOrRetrieveResult createOrRetrieve(const std::string& name,
																const std::string& group, bool isManual = false,
																ManualResourceLoader* loader = 0,
																const NameValuePairList* createParams = 0);
		virtual void setMemoryBudget(size_t bytes);
		virtual size_t getMemoryBudget(void) const;
		virtual size_t getMemoryUsage(void) const {return mMemoryUsage.get();}
		
		virtual void unload(const std::string& name);
		virtual void unload(ResourceHandle handle);
		virtual void unloadAll(bool reloadableOnly = true);
		virtual void reloadAll(bool reloadableOnly = true);
		virtual void unloadUnreferencedResources(bool reloadableOnly = true);
		virtual void reloadUnreferencedResources(bool reloadableOnly = true);
		virtual void remove(ResourcePtr& r);
		virtual void remove(const std::string& name);
		virtual void remove(ResourceHandle handle);
		virtual void removeAll(void);
		virtual void removeUnreferencedResources(bool reloadableOnly = true);
		virtual ResourcePtr getByName(const std::string& name, const std::string& groupName = ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME);
		virtual ResourcePtr getByHandle(ResourceHandle handle);
		virtual bool resourceExists(const std::string& name)
		{
			return !getByName(name).isNull();
		}
		
		virtual bool resourceExists(ResourceHandle handle)
		{
			return !getByHandle(handle).isNull();
		}
		virtual void _notifyResourceTouched(Resource* res);
		virtual void _notifyResourceLoaded(Resource* res);
		virtual void _notifyResourceUnloaded(Resource* res);
		virtual ResourcePtr prepare(const std::string& name,
									const std::string& group, bool isManual = false,
									ManualResourceLoader* loader = 0, const NameValuePairList* loadParams = 0,
									bool backgroundThread = false);
		
		virtual ResourcePtr load(const std::string& name,
								 const std::string& group, bool isManual = false,
								 ManualResourceLoader* loader = 0, const NameValuePairList* loadParams = 0,
								 bool backgroundThread = false);
		
		virtual const StringVector& getScriptPatterns(void) const {return mScriptPatterns;}
		
		virtual void parseScript(DataStreamPtr& stream, const std::string& groupName)
		{
			(void)stream; (void)groupName;
		}
		
		virtual float getLoadingOrder(void) const {return mLoadOrder;}
		
		virtual void setVerbose(bool v) {mVerbose = v;}
		
		virtual bool getVerbose(void) {return mVerbose;}
		
		class ResourcePool : public Pool<ResourcePtr>
		{
		protected:
			std::string mName;
		public:
			ResourcePool(const std::string& name);
			~ResourcePool();
			const std::string& getName() const;
			void clear();
		};
		
		ResourcePool* getResourcePool(const std::string& name);
		void destroyResourcePool(ResourcePool* pool);
		void destroyResourcePool(const std::string& name);
		void destroyAllResourcePools();
		
	protected:
		ResourceHandle getNextHandle(void);
		
		virtual Resource* createImpl(const std::string& name, ResourceHandle handle,
									 const std::string& group, bool isManual, ManualResourceLoader* loader,
									 const NameValuePairList* createParams) = 0;
		virtual void addImpl(ResourcePtr& res);
		virtual void removeImpl(ResourcePtr& res);
		virtual void checkUsage(void);
		
	public:
		typedef HashMap<std::string, ResourcePtr> ResourceMap;
		typedef HashMap<std::string, ResourceMap> ResourceWithGroupMap;
		typedef map<ResourceHandle, ResourcePtr> ResourceHandleMap;
	protected:
		ResourceHandleMap mResourcesByHandle;
		ResourceMap mResources;
		ResourceWithGroupMap mResourceWithGroup;
		ResourceHandle mNextHandle;
		size_t mMemoryBudget;
		AtomicScalar<size_t> mMemoryUsage;
		
		bool mVerbose;
		
		StringVector mScriptPatterns;
		float mLoadOrder;
		std::string mResourceType;
		
	public:
		typedef MapIterator<ResourceHandleMap> ResourceMapIterator;
		
		ResourceMapIterator getResourceIterator(void)
		{
			return ResourceMapIterator(mResourcesByHandle.begin(), mResourcesByHandle.end());
		}
		
	protected:
		typedef map<std::string, ResourcePool*> ResourcePoolMap;
		ResourcePoolMap mResourcePoolMap;
	};
}

#endif
